package com.fessc.develop.handler.processor.callback;

import com.alibaba.fastjson.JSON;
import com.fessc.develop.base.CCBResult;
import com.fessc.develop.entity.dbvo.SettleTrade;
import com.fessc.develop.entity.dbvo.SettleTradeList;
import com.fessc.develop.entity.ccbvo.*;
import com.fessc.develop.model.enums.EnumPaymentStatus;
import com.fessc.develop.model.enums.EnumResultType;
import com.fessc.develop.model.enums.EnumServiceCode;
import com.fessc.develop.service.interfaces.ISettleTradeListService;
import com.fessc.develop.service.interfaces.ISettleTradeService;
import com.fessc.develop.utils.BusiUtil;
import com.fessc.develop.utils.DateUtil;
import com.fessc.develop.utils.ErrorUtil;
import com.fessc.develop.utils.ExceptionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class CCBSettleTradeCallBackProcessor implements CCBICallBackProcessor {

    @Resource
    private ISettleTradeService settleTradeService;

    @Resource
    private ISettleTradeListService settleTradeListService;

    @Override
    public String getServiceCode() {
        return EnumServiceCode.CCB_HMT006.toString();
    }

    /**
     * 跨境付汇交易结果回调
     *
     * @param ccbSettleTradeCallBackVo 跨境付汇交易结果回调报文
     * @return 返回结果
     */
    @Override
    public CCBResult<CCBResponseBodyVo> settleTradeStatusProcess(CCBSettleTradeCallBackVo ccbSettleTradeCallBackVo) {
        log.info("建行跨境付汇回调通知处理开始");
        String errorCode = check(ccbSettleTradeCallBackVo);
        CCBResponseHeadVo responseHeadVo = new CCBResponseHeadVo(EnumResultType.CCB_SUCCESS.getStatusCode(), EnumResultType.CCB_SUCCESS.getMsg());
        CCBResponseBodyVo responseBodyVo = new CCBResponseBodyVo(EnumResultType.CCB_SUCCESS.getStatusCode(), EnumResultType.CCB_SUCCESS.getMsg());
        List<CCBSettleTradeOrderVo> ordrNos = ccbSettleTradeCallBackVo.getOrdrNos();

        //判断订单编号、业务类型、交易结果是否为空，是否符合报文要求
        if (BusiUtil.isNotNull(errorCode)) {
            responseBodyVo.setFalrs(ErrorUtil.getErrorDesc(errorCode));
            responseBodyVo.setPsgrlt(EnumResultType.CCB_FAIL.getStatusCode());
            return new CCBResult<>(responseHeadVo, responseBodyVo);
        }

        //判断订单编号是否正确
        SettleTrade settleTrade = settleTradeService.getSettleTradeByOrderNos(ccbSettleTradeCallBackVo.getOrdrNo());
        String[] args = {ccbSettleTradeCallBackVo.getOrdrNo()};
        if (BusiUtil.isNull(settleTrade)) {
            responseBodyVo.setFalrs(ErrorUtil.getParseErrorDesc("EE1005", args));
            responseBodyVo.setPsgrlt(EnumResultType.CCB_FAIL.getStatusCode());
            return new CCBResult<>(responseHeadVo, responseBodyVo);
        }

        //根据请求报文，更改交易明细状态
        List<SettleTradeList> settleTradeLists = new ArrayList<SettleTradeList>();
        ordrNos.forEach(order ->
                {
                    SettleTradeList settleList = new SettleTradeList();
                    settleList.setSuborderno(order.getSubOrderNo());
                    if (BusiUtil.isEquals(EnumResultType.CCB_SUCCESS.getStatusCode(), order.getTxnRlt())) {
                        log.info("建行跨境付汇明细订单交易结果回调通知，交易成功：" + order.getSubOrderNo());
                        settleList.setSerialnumberStatus(EnumResultType.CCB_SETTLE_TRADE_SUCCESS.getStatusCode());  //已跨境付汇
                        settleTradeLists.add(settleList);
                    } else if (BusiUtil.isEquals(EnumResultType.CCB_FAIL.getStatusCode(), order.getTxnRlt())) {
                        log.info("建行跨境付汇明细订单交易结果回调通知，交易失败：" + order.getSubOrderNo());
                        settleList.setSerialnumberStatus(EnumResultType.CCB_SETTLE_TRADE_FAIL.getStatusCode());  //未跨境付汇
                        settleTradeLists.add(settleList);
                    } else {
                        log.info("建行跨境付汇明细订单交易结果回调通知，返回状态字段值错误：" + order.getSubOrderNo());
                    }
                }
        );

        if (BusiUtil.isNotNull(ccbSettleTradeCallBackVo) && BusiUtil.isNotNull(ccbSettleTradeCallBackVo.getOrdrNo())) {
            // 将review_status更改为2，deal_date为当前时间，deal_performer为银行直连机构号，review_date为当前时间
            // 将review_performer为银行直连机构号，send2更改为N，serialnumber更改实际的跨境付款流水号
            log.info("建行跨境付汇汇总订单交易结果回调通知，交易成功：" + ccbSettleTradeCallBackVo.getOrdrNo());
            settleTrade.setReviewStatus("2"); //银行审核付款成功
            settleTrade.setDealDate(DateUtil.getCurrentLocalDateTime());
            settleTrade.setDealPerformer(settleTrade.getOrgCode()); //银行直连机构号
            settleTrade.setReviewDate(DateUtil.getCurrentLocalDateTime());
            settleTrade.setReviewPerformer(settleTrade.getOrgCode()); //银行直连机构号
            settleTrade.setSerialnumber(settleTrade.getSettleId());  //建行没有汇总订单的付款流水号，用settle_id代替
            settleTrade.setSend2("N");
        }

        // 更新跨境订单交易表
        log.info("更新建行跨境付汇订单状态为成功：" + settleTrade.getOrderno());
        settleTradeService.updateSettleTradeStatusRefidsLog(settleTrade, EnumPaymentStatus.PAYMENT_SUCCESS.toString());

        // 更新跨境订单明细表
        log.info("更新建行跨境付订单汇明细状态：" + settleTrade.getOrderno());
        if (BusiUtil.isNotNull(settleTradeLists) && !settleTradeListService.updateSettleTradeListStatusByOrderNo(settleTradeLists, settleTrade.getOrderno(), settleTrade.getSettleId())) {
            throw ExceptionUtil.businessException("EE1004");
        }

        // 返回响应
        CCBResult<CCBResponseBodyVo> ccbResult = new CCBResult<>(responseHeadVo, responseBodyVo);
        log.info("建行跨境付汇回调通知处理结束，返回报文：" + JSON.toJSONString(ccbResult));
        return ccbResult;
    }

    /**
     * 预付款、退款交易结果回调
     *
     * @param ccbPrePaymentCallBackVo 预付款交易结果回调报文
     * @return 返回结果
     */
    @Override
    public CCBResult<CCBResponseBodyVo> paymentStatusProcess(CCBPrePaymentCallBackVo ccbPrePaymentCallBackVo) {
        return null;
    }

    private String check(CCBSettleTradeCallBackVo ccbSettleTradeCallBackVo) {
        List<CCBSettleTradeOrderVo> ordrNos = ccbSettleTradeCallBackVo.getOrdrNos();
        List<String> subOrderNoList = new ArrayList<>();

        // 检查报文汇总订单编号，订单编号是否为空
        if (BusiUtil.isNull(ordrNos) || ordrNos.isEmpty() || BusiUtil.isNull(ccbSettleTradeCallBackVo.getTotalCount()) ) {
            return "EE1009";
        }

        if (BusiUtil.isNotEquals(ccbSettleTradeCallBackVo.getTotalCount(), String.valueOf(ordrNos.size()))) {
            return "EE1016";
        }
        // 检查清算结果：00-成功；01-失败；02-未清算
        for (CCBSettleTradeOrderVo order : ordrNos) {
            subOrderNoList.add(order.getSubOrderNo());
            if (BusiUtil.isNotEquals(order.getTxnRlt(), EnumResultType.CCB_SUCCESS.getStatusCode()) &&
                    BusiUtil.isNotEquals(order.getTxnRlt(), EnumResultType.CCB_FAIL.getStatusCode())) {
                return "EE1008";
            }
        }

        // 检查请求报文的订单明细是否在存在
        List<SettleTradeList> reqList = settleTradeListService.getSettleTradeListBySubOrderNos(ccbSettleTradeCallBackVo.getOrdrNo(), subOrderNoList);
        if (BusiUtil.isNull(reqList) || reqList.isEmpty() || BusiUtil.isNull(ordrNos)) {
            return "EE1015";
        }

        // 检查请求报文的订单明细总数是否一致
        if (BusiUtil.isNotEquals(String.valueOf(reqList.size()), String.valueOf(ordrNos.size()))) {
            return "EE1016";
        }

        // 查询请求订单号对应的明细数据
        List<SettleTradeList> dataList = settleTradeListService.getSettleTradeListBySubOrderNos(ccbSettleTradeCallBackVo.getOrdrNo(), null);

        // 检查请求报文的订单明细与数据库保存是否一致
        if (BusiUtil.isNotEquals(String.valueOf(reqList.size()), String.valueOf(dataList.size()))) {
            return "EE1016";
        }
        return "";
    }

    /**
     * 借助Map来获取listA、listB的相同元素集合
     *
     * @param settleTradeLists 跨境付汇集合
     * @param settleTradeOrders 返回集合
     * @return list<SettleTradeList> 返回集合
     */
    public static List<SettleTradeList> getDifferListByMap(List<SettleTradeList> settleTradeLists, List<CCBSettleTradeOrderVo> settleTradeOrders) {
        List<SettleTradeList> differList = new ArrayList<>();
        Map<String, SettleTradeList> listAMap = new HashMap<>();
        Map<String, CCBSettleTradeOrderVo> listBMap = new HashMap<>();
        for (SettleTradeList settleTradeList : settleTradeLists) {
            listAMap.put(settleTradeList.getSuborderno(), settleTradeList);
        }
        for (CCBSettleTradeOrderVo orderVo : settleTradeOrders) {
            listBMap.put(orderVo.getSubOrderNo(), orderVo);
        }
        for (Map.Entry<String, SettleTradeList> entry : listAMap.entrySet()) {
            CCBSettleTradeOrderVo settleTradeOrderVo = listBMap.get(entry.getKey());
            SettleTradeList settleTradeList = entry.getValue();
            if (BusiUtil.isNotNull(settleTradeOrderVo)) {
                if (BusiUtil.isEquals(EnumResultType.CCB_SUCCESS.getStatusCode(), settleTradeOrderVo.getTxnRlt())) {
                    log.info("建行跨境付汇明细订单交易结果回调通知，交易成功：" + settleTradeOrderVo.getSubOrderNo());
                    settleTradeList.setSerialnumberStatus(EnumResultType.CCB_SETTLE_TRADE_SUCCESS.getStatusCode());  //已跨境付汇
                    differList.add(settleTradeList);
                } else if (BusiUtil.isEquals(EnumResultType.CCB_FAIL.getStatusCode(), settleTradeOrderVo.getTxnRlt())) {
                    log.info("建行跨境付汇明细订单交易结果回调通知，交易失败：" + settleTradeOrderVo.getSubOrderNo());
                    settleTradeList.setSerialnumberStatus(EnumResultType.CCB_SETTLE_TRADE_FAIL.getStatusCode());  //未跨境付汇
                    differList.add(settleTradeList);
                } else {
                    log.info("建行跨境付汇明细订单交易结果回调通知，返回状态字段值错误：" + settleTradeOrderVo.getSubOrderNo());
                }
            } else {
                log.info("建行跨境付汇明细订单交易结果回调通知明细订单号错误：" + settleTradeOrderVo.getSubOrderNo());
            }
        }
        return differList;
    }

}
